package com.hl.yyx.modules.ums.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hl.yyx.common.api.ApiData;
import com.hl.yyx.common.constants.Constants;
import com.hl.yyx.common.exception.ApiException;
import com.hl.yyx.common.exception.Asserts;
import com.hl.yyx.common.response.ObjectResponse;
import com.hl.yyx.common.response.Response;
import com.hl.yyx.common.response.SuccessResponse;
import com.hl.yyx.common.util.IpUtil;
import com.hl.yyx.common.util.JwtTokenUtil;
import com.hl.yyx.domain.AdminUserDetails;
import com.hl.yyx.dto.IdDTO;
import com.hl.yyx.dto.QueryBuilder;
import com.hl.yyx.dto.SearchFilters;
import com.hl.yyx.modules.ums.dto.AssignRoleDTO;
import com.hl.yyx.modules.ums.dto.UpdatePassDTO;
import com.hl.yyx.modules.ums.mapper.UmsAdminMapper;
import com.hl.yyx.modules.ums.mapper.UmsSourceMapper;
import com.hl.yyx.modules.ums.model.UmsAdmin;
import com.hl.yyx.modules.ums.model.UmsAdminRole;
import com.hl.yyx.modules.ums.model.UmsSource;
import com.hl.yyx.modules.ums.service.UmsAdminRoleService;
import com.hl.yyx.modules.ums.service.UmsAdminService;
import com.hl.yyx.modules.ums.service.UmsRoleService;
import com.hl.yyx.modules.ums.vo.UmsAdminVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 管理员表 服务实现类
 * </p>
 *
 * @author hl243695czyn
 * @since 2022-06-20
 */
@Service
public class UmsAdminServiceImpl extends ServiceImpl<UmsAdminMapper, UmsAdmin> implements UmsAdminService {
    private static final Logger LOGGER = LoggerFactory.getLogger(UmsAdminServiceImpl.class);

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    UmsAdminRoleService adminRoleService;

    @Autowired
    UmsRoleService roleService;

    @Autowired
    UmsAdminMapper adminMapper;

    @Autowired
    UmsSourceMapper sourceMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 分页查询
     *
     * @param searchFilters
     * @return
     */
    @Override
    public Response pageList(SearchFilters<UmsAdmin> searchFilters) {
        Page<UmsAdmin> page = new Page<>(searchFilters.getPageIndex(), searchFilters.getPageSize());
        QueryWrapper<UmsAdmin> queryWrapper = QueryBuilder.build(searchFilters);
        Page<UmsAdmin> pageList = page(page, queryWrapper);
        List<UmsSource> sourceList = sourceMapper.selectList(null);
        HashMap<String, UmsSource> sourceMap = new HashMap<>();
        sourceList.stream().forEach(item -> {
            sourceMap.put(item.getId(), item);
        });
        ArrayList<UmsAdmin> dataList = new ArrayList<>();
        pageList.getRecords().stream().forEach(item -> {
            UmsAdminVO vo = new UmsAdminVO();
            BeanUtil.copyProperties(item, vo);
            if (item.getAvatar() != null && sourceMap.get(item.getAvatar()) != null) {
                vo.setAvatarSource(sourceMap.get(item.getAvatar()));
            }
            dataList.add(vo);
        });
        return new ObjectResponse<>(new ApiData<>(dataList, pageList.getTotal()));
    }

    /**
     * 添加用户
     *
     * @param umsAdmin
     * @return
     */
    @Transactional
    @Override
    public Response create(UmsAdmin umsAdmin) {
        UmsAdmin account = adminMapper.selectByAccount(umsAdmin.getAccount());
        if (account != null) {
            throw new ApiException("登录账号已存在");
        }
        UmsAdmin admin = adminMapper.selectByUsername(umsAdmin.getUsername());
        if (admin != null) {
            throw new ApiException("姓名已存在");
        }
        UmsAdmin user = adminMapper.selectByTelephone(umsAdmin.getTelephone());
        if (user != null) {
            throw new ApiException("手机号已存在");
        }
        // 设置用户初始密码,将初始密码进行md5加密，再进行crypto加密，相当于加密两次，前端登录时，现在前端进行md5加密
        String encodedPassword = passwordEncoder.encode(getMD5Hash(Constants.INIT_PASSWORD));
        umsAdmin.setPassword(encodedPassword);
        save(umsAdmin);
        return new SuccessResponse();
    }

    public static String getMD5Hash(String input) {
        try {
            // 1. 获取MD5 MessageDigest实例
            MessageDigest md = MessageDigest.getInstance("MD5");

            // 2. 计算哈希值（返回字节数组）
            byte[] hashBytes = md.digest(input.getBytes());

            // 3. 将字节数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = String.format("%02x", b & 0xff);
                hexString.append(hex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("MD5算法不存在", e);
        }
    }

    /**
     * 更新用户
     *
     * @param umsAdmin
     * @return
     */
    @Transactional
    @Override
    public Response updateAdmin(UmsAdmin umsAdmin) {
        UmsAdmin entity = adminMapper.hFindById(umsAdmin.getId());
        String password = entity.getPassword();
        BeanUtil.copyProperties(umsAdmin, entity);
        entity.setPassword(password);
        updateById(entity);
        return new SuccessResponse();
    }

    /**
     * 查看用户
     *
     * @param idDTO
     * @return
     */
    @Override
    public Response view(IdDTO idDTO) {
        return new ObjectResponse<>(adminMapper.hFindById(idDTO.getId()));
    }

    /**
     * 删除用户
     *
     * @param idDTO
     * @return
     */
    @Transactional
    @Override
    public Response delete(IdDTO idDTO) {
        UmsAdmin admin = adminMapper.hFindById(idDTO.getId());
        if (admin.getAccount().equals("admin")) {
            throw new ApiException("超级管理员不允许删除");
        }
        adminMapper.hDeleteById(idDTO.getId());
        // 清空当前用户的所有角色
        QueryWrapper<UmsAdminRole> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdminRole::getAdminId, idDTO.getId());
        adminRoleService.remove(wrapper);
        return new SuccessResponse();
    }

    /**
     * 根据用户名获取用户
     *
     * @param account 用户名
     * @return
     */
    @Override
    public AdminUserDetails loadUserByAccount(String account) {
        UmsAdmin admin = getAdminByUsername(account);
        if (admin != null) {
            return new AdminUserDetails(admin);
        }
        throw new ApiException("用户不存在");
    }

    /**
     * 登录
     *
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @Override
    public String login(String username, String password, HttpServletRequest request) {
        String token = null;
        try {
            AdminUserDetails userDetails = loadUserByAccount(username);
            if (userDetails == null) {
                Asserts.fail("用户名不存在");
            }
            // 密码加密
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                Asserts.fail("密码错误");
            }
            // 生成springSecurity的通过认证标识
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
            // 更新上次登录时间和登录ip
            UmsAdmin currentAdmin = getCurrentAdmin();
            UpdateWrapper<UmsAdmin> updateWrapper = new UpdateWrapper<>();
            updateWrapper.lambda().eq(UmsAdmin::getId, currentAdmin.getId());
            updateWrapper.set("last_login_ip", IpUtil.getIpAddr(request));
            updateWrapper.set("last_login_time", new Date());
            update(updateWrapper);
        } catch (AuthenticationException e) {
            LOGGER.warn("登录异常：{}", e.getMessage());
        }
        return token;
    }

    /**
     * 修改密码
     *
     * @return
     */
    @Override
    public Response updatePass(UpdatePassDTO passDTO) {
        UpdateWrapper<UmsAdmin> updateWrapper = new UpdateWrapper<>();
        updateWrapper.lambda().eq(UmsAdmin::getId, passDTO.getId());
        updateWrapper.set("password", passDTO.getPassword());
        update(updateWrapper);
        return new SuccessResponse();
    }

    @Override
    public Response viewAssignRole(IdDTO idDTO) {
        UmsAdmin admin = adminMapper.hFindById(idDTO.getId());
        // 查询用户所有的角色id
        QueryWrapper<UmsAdminRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UmsAdminRole::getAdminId, admin.getId());
        List<UmsAdminRole> adminRoleList = adminRoleService.list(queryWrapper);
        List<String> roleIds = adminRoleList.stream().map(UmsAdminRole::getRoleId).collect(Collectors.toList());
        return new ObjectResponse<>(roleIds);
    }

    @Override
    @Transactional
    public Response setAssignRole(AssignRoleDTO assignRoleDTO) {
        // 清空当前用户的所有角色
        QueryWrapper<UmsAdminRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(UmsAdminRole::getAdminId, assignRoleDTO.getUserId());
        adminRoleService.remove(queryWrapper);

        List<UmsAdminRole> umsAdminRoles = setAdminAndRole(assignRoleDTO.getRoleIds(), assignRoleDTO.getUserId());
        adminRoleService.saveBatch(umsAdminRoles);
        return new SuccessResponse();
    }

    /**
     * 设置用户和角色的关联关系
     *
     * @param roleList 角色列表
     * @param userId   用户id
     * @return
     */
    public List<UmsAdminRole> setAdminAndRole(List<String> roleList, String userId) {
        List<UmsAdminRole> adminRoleList = new ArrayList<>();
        for (String roleId : roleList) {
            UmsAdminRole adminRole = new UmsAdminRole();
            adminRole.setAdminId(userId);
            adminRole.setRoleId(roleId);
            adminRoleList.add(adminRole);
        }
        return adminRoleList;
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param account 用户名
     * @return
     */
    public UmsAdmin getAdminByUsername(String account) {
        QueryWrapper<UmsAdmin> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UmsAdmin::getAccount, account);
        return getOne(wrapper);
    }

    /**
     * 获取当前用户
     *
     * @return
     */
    public UmsAdmin getCurrentAdmin() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        AdminUserDetails admin = (AdminUserDetails) authentication.getPrincipal();
        UmsAdmin umsAdmin = admin.getUmsAdmin();
        return umsAdmin;
    }

}
